﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DuplicateFileFinderGUI
{
    public partial class Form1 : Form
    {
        // 用于存储找到的重复文件组
        private Dictionary<string, List<FileInfo>> _duplicateGroups = new Dictionary<string, List<FileInfo>>();

        public Form1()
        {
            InitializeComponent();
        }

        private void btnBrowse_Click(object sender, EventArgs e)
        {
            using (var folderDialog = new FolderBrowserDialog())
            {
                folderDialog.Description = "请选择要扫描的目录";
                if (folderDialog.ShowDialog() == DialogResult.OK)
                {
                    txtFolderPath.Text = folderDialog.SelectedPath;
                    // 当选择新目录时，清空之前的结果
                    listViewResults.Items.Clear();
                    _duplicateGroups.Clear();
                    btnDelete.Enabled = false;
                }
            }
        }

        private async void btnFind_Click(object sender, EventArgs e)
        {
            string targetDirectory = txtFolderPath.Text;
            if (!Directory.Exists(targetDirectory))
            {
                MessageBox.Show("请先选择一个有效的目录。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            // 禁用按钮，防止重复点击
            btnFind.Enabled = false;
            btnBrowse.Enabled = false;
            btnDelete.Enabled = false;
            btnAutoDelete.Enabled = false;
            statusLabel.Text = "正在扫描文件，请稍候...";
            listViewResults.Items.Clear();
            _duplicateGroups.Clear();

            try
            {
                // 使用 Task.Run 将耗时操作放入后台线程，防止界面卡死
                var groups = await Task.Run(() => FindDuplicateFiles(targetDirectory));
                _duplicateGroups = groups;
                DisplayResults(groups);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"扫描过程中发生错误: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                // 恢复按钮状态
                btnFind.Enabled = true;
                btnBrowse.Enabled = true;        
                statusLabel.Text = "扫描完成";
            }
        }

        /// <summary>
        /// 在指定目录下查找内容重复的文件。
        /// </summary>
        /// <param name="rootDir">要搜索的根目录。</param>
        /// <returns>一个字典，键是文件内容的MD5哈希值，值是内容相同的FileInfo列表。</returns>
        private Dictionary<string, List<FileInfo>> FindDuplicateFiles(string rootDir)
        {
            // 1. 按文件大小分组
            var sizeGroups = new Dictionary<long, List<FileInfo>>();

            foreach (var file in Directory.EnumerateFiles(rootDir, "*.*", SearchOption.AllDirectories))
            {
                try
                {
                    var fileInfo = new FileInfo(file);
                    if (fileInfo.Length > 0 && !fileInfo.Attributes.HasFlag(FileAttributes.System) && !fileInfo.Attributes.HasFlag(FileAttributes.Hidden))
                    {
                        if (!sizeGroups.ContainsKey(fileInfo.Length))
                        {
                            sizeGroups[fileInfo.Length] = new List<FileInfo>();
                        }
                        sizeGroups[fileInfo.Length].Add(fileInfo);
                    }
                }
                catch (UnauthorizedAccessException) { /* 忽略无权限文件 */ }
                catch (PathTooLongException) { /* 忽略路径过长文件 */ }
                catch (IOException) { /* 忽略其他IO异常 */ }
            }

            // 过滤掉只有一个文件的大小组
            var potentialDuplicatesBySize = sizeGroups.Where(g => g.Value.Count > 1)
                                                      .SelectMany(g => g.Value)
                                                      .ToList();

            // 2. 按文件内容(MD5哈希)分组
            var contentGroups = new Dictionary<string, List<FileInfo>>();
            foreach (var fileInfo in potentialDuplicatesBySize)
            {
                try
                {
                    string fileHash = CalculateMD5(fileInfo.FullName);
                    if (!contentGroups.ContainsKey(fileHash))
                    {
                        contentGroups[fileHash] = new List<FileInfo>();
                    }
                    contentGroups[fileHash].Add(fileInfo);
                }
                catch (IOException) { /* 忽略无法读取的文件 */ }
            }

            // 过滤掉只有一个文件的内容组
            return contentGroups.Where(g => g.Value.Count > 1)
                                .ToDictionary(g => g.Key, g => g.Value);
        }

        /// <summary>
        /// 计算文件的MD5哈希值。
        /// </summary>
        private string CalculateMD5(string filePath)
        {
            using (var md5 = MD5.Create())
            using (var stream = File.OpenRead(filePath))
            {
                byte[] hashBytes = md5.ComputeHash(stream);
                return BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant();
            }
        }

        /// <summary>
        /// 在ListView中显示查找结果。
        /// </summary>
        private void DisplayResults(Dictionary<string, List<FileInfo>> duplicateGroups)
        {
            if (duplicateGroups.Count == 0)
            {
                statusLabel.Text = "未找到任何重复文件。";
                return;
            }

            int groupId = 1;
            foreach (var group in duplicateGroups)
            {
                foreach (var fileInfo in group.Value)
                {
                    var item = new ListViewItem(new[]
                    {
                groupId.ToString(),                      // 组ID
                fileInfo.Name,                           // 文件名（含后缀）
                fileInfo.FullName,                       // 【关键修改】完整文件路径（目录+文件名）
                (fileInfo.Length / 1024).ToString("N0"), // 大小(KB)
                group.Key                                // MD5
            });
                    listViewResults.Items.Add(item);
                }
                groupId++;
            }

            statusLabel.Text = $"共找到 {duplicateGroups.Count} 组重复文件，总计 {listViewResults.Items.Count} 个文件。";
            btnDelete.Enabled = true;
            btnAutoDelete.Enabled = true;
        }

        private void btnDelete_Click(object sender, EventArgs e)
        {
            if (listViewResults.SelectedItems.Count == 0)
            {
                MessageBox.Show("请先从列表中选择要删除的文件。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            var confirmResult = MessageBox.Show(
                $"您确定要删除选中的 {listViewResults.SelectedItems.Count} 个文件吗？\n此操作不可撤销！",
                "确认删除",
                MessageBoxButtons.YesNo,
                MessageBoxIcon.Warning
            );

            if (confirmResult == DialogResult.Yes)
            {
                int deletedCount = 0;
                int failedCount = 0;

                // 禁用按钮
              //  btnDelete.Enabled = false;
                btnFind.Enabled = false;
                btnBrowse.Enabled = false;
                statusLabel.Text = "正在删除文件，请稍候...";

                // 从选中项中获取文件路径并删除
                foreach (ListViewItem item in listViewResults.SelectedItems)
                {
                    string filePath = item.SubItems[2].Text; // "路径"列
                    try
                    {
                        File.Delete(filePath);
                        deletedCount++;
                        // 从ListView中移除已删除的项
                        listViewResults.Items.Remove(item);
                    }
                    catch (Exception ex)
                    {
                        failedCount++;
                        Console.WriteLine($"删除文件失败: {filePath}, 错误: {ex.Message}");
                    }
                }

                // 更新状态
                statusLabel.Text = $"删除完成：成功 {deletedCount} 个，失败 {failedCount} 个";

                // 如果列表为空，清除_groups字典
                if (listViewResults.Items.Count == 0)
                {
                    _duplicateGroups.Clear();
                }

                // 恢复按钮
                btnFind.Enabled = true;
                btnBrowse.Enabled = true;
                btnDelete.Enabled = true;
            }
        }

        /// <summary>
        /// 自动删除：保留每组重复文件中“最早创建”的文件（创建时间相同则按路径排序），删除同组其他文件
        /// </summary>
        private async void btnAutoDelete_Click(object sender, EventArgs e)
        {
            // 1. 校验是否有重复文件可删
            if (_duplicateGroups.Count == 0 || listViewResults.Items.Count == 0)
            {
                MessageBox.Show("未找到任何重复文件，无法执行自动删除。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            // 2. 提示用户自动删除规则（明确告知保留逻辑），确认操作
            var confirmResult = MessageBox.Show(
                "自动删除规则：\n1. 每组重复文件优先保留「最早创建」的文件；\n2. 若创建时间相同，保留「文件路径字母排序最靠前」的文件；\n3. 删除同组其他所有重复文件！\n\n此操作不可撤销，是否继续？",
                "确认自动删除",
                MessageBoxButtons.YesNo,
                MessageBoxIcon.Warning
            );
            if (confirmResult != DialogResult.Yes)
            {
                return; // 用户取消操作
            }

            // 3. 禁用所有按钮，防止重复操作，更新状态
            btnFind.Enabled = false;
            btnBrowse.Enabled = false;
          //  btnDelete.Enabled = false;
           // btnAutoDelete.Enabled = false;
            statusLabel.Text = "正在自动删除重复文件，请稍候...";

            // 4. 异步执行删除（避免界面卡死）
            await Task.Run(() =>
            {
                int totalDeleted = 0; // 总删除成功数
                int totalFailed = 0;  // 总删除失败数

                // 遍历所有重复文件组（_duplicateGroups：Key=MD5，Value=同组文件列表）
                foreach (var group in _duplicateGroups)
                {
                    List<FileInfo> filesInGroup = group.Value; // 组内所有重复文件

                    // 【核心规则修改】优先按创建时间升序（最早在前），再按路径升序（字母靠前在前）
                    FileInfo fileToKeep = filesInGroup
                        .OrderBy(f => f.CreationTime)       // 第一排序：创建时间（最早的排前面）
                        .ThenBy(f => f.FullName)            // 第二排序：文件路径（字母靠前的排前面）
                        .First();                           // 取排序后的第一个文件（要保留的文件）

                    // 筛选出组内需要删除的文件（排除要保留的文件）
                    List<FileInfo> filesToDelete = filesInGroup
                        .Where(f => f.FullName != fileToKeep.FullName) // 用完整路径确保唯一匹配
                        .ToList();

                    // 遍历删除组内待删除文件
                    foreach (var fileToDel in filesToDelete)
                    {
                        try
                        {
                            // 双重校验：文件存在且未被删除（避免重复删除或文件已被移动）
                            if (File.Exists(fileToDel.FullName))
                            {
                                File.Delete(fileToDel.FullName);
                                totalDeleted++;

                                // 【同步更新界面】从ListView中移除已删除的文件（后台线程需用Invoke）
                                Invoke(new Action(() =>
                                {
                                    // 通过“完整路径”匹配ListView中的项（确保精准找到）
                                    ListViewItem itemToRemove = listViewResults.Items
                                        .Cast<ListViewItem>()
                                        .FirstOrDefault(item => item.SubItems[2].Text == fileToDel.FullName);
                                    if (itemToRemove != null)
                                    {
                                        listViewResults.Items.Remove(itemToRemove);
                                    }
                                }));
                            }
                        }
                        catch (IOException ex)
                        {
                            // 处理“文件被占用”“路径过长”等IO异常
                            totalFailed++;
                            Console.WriteLine($"删除失败（{fileToDel.FullName}）：文件被占用或路径错误，{ex.Message}");
                        }
                        catch (UnauthorizedAccessException ex)
                        {
                            // 处理“权限不足”异常（如系统文件、只读文件）
                            totalFailed++;
                            Console.WriteLine($"删除失败（{fileToDel.FullName}）：无删除权限，{ex.Message}");
                        }
                    }
                }

                // 5. 删除完成后，更新状态、缓存和界面
                Invoke(new Action(() =>
                {
                    // 清除重复文件缓存（所有组已处理，缓存失效）
                    _duplicateGroups.Clear();

                    // 更新状态栏：显示详细结果
                    statusLabel.Text = $"自动删除完成！成功删除 {totalDeleted} 个重复文件，失败 {totalFailed} 个文件。";

                    // 禁用删除按钮（已无重复文件可删）
                    btnDelete.Enabled = false;
                    btnAutoDelete.Enabled = false;

                    // 恢复基础操作按钮（重新扫描等）
                    btnFind.Enabled = true;
                    btnBrowse.Enabled = true;

                    // 弹窗提示最终结果（提升用户感知）
                    MessageBox.Show(
                        $"自动删除结果：\n✅ 成功删除：{totalDeleted} 个重复文件\n❌ 删除失败：{totalFailed} 个文件\n",
                        "自动删除完成",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Information
                    );
                }));
            });
        }
    }
}
